package client

import (
	"errors"
	"gitee.com/yangzx6606/core/pattern"
	"net"
	"time"
)

// TcpClient TCP客户端
type TcpClient struct {
	pattern.AbstractSubject[*Packet]
	address     string
	conn        net.Conn
	isOpened    bool
	isConnected bool
}

func NewTcpClient(address string) *TcpClient {
	return &TcpClient{address: address}
}

func (c *TcpClient) Open() error {
	if c.isOpened {
		return errors.New("已打开")
	}
	c.isOpened = true
	go c.doWork()
	return nil
}

func (c *TcpClient) Close() {
	if c.isOpened {
		c.isOpened = false
		_ = c.conn.Close()
	}
}

func (c *TcpClient) Write(data *Packet) error {
	if !c.isConnected {
		return errors.New("未连接")
	}
	if data.Data != nil && data.Type == PacketTypeData {
		_, err := c.conn.Write(data.Data)
		return err
	}
	return errors.New("数据包不正确")
}

func (c *TcpClient) doWork() {
	buffer := make([]byte, 1024*128)
	for c.isOpened {
		if c.tryConnect() != nil {
			time.Sleep(time.Second * 3)
			continue
		}
		n, err := c.conn.Read(buffer)
		if err != nil {
			if c.isOpened {
				c.isConnected = false
				_ = c.conn.Close()
				c.Notify(NewPacket(PacketTypeConnectLost, nil))
				time.Sleep(time.Second * 3)
			}
			continue
		}
		c.Notify(NewPacket(PacketTypeData, buffer[:n]))
	}
}

func (c *TcpClient) tryConnect() error {
	if c.isConnected {
		return nil
	}
	var err error
	c.conn, err = net.Dial("tcp", c.address)
	if err != nil {
		return err
	}
	c.isConnected = true
	c.Notify(NewPacket(PacketTypeConnected, nil))
	return nil
}
